
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include "../luaUnity.h"
#include "../global.h"
#include <iostream>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <thread>

#include <boost/filesystem.hpp>
#include <log/log.h>
#include <appendix/phy_constants.h>
#include <boost/signals2/signal.hpp>
#include <boost/bind.hpp>
#include <boost/regex.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/locale.hpp>
#include <boost/process.hpp>
namespace LuaHelp{
	sol::table open_luaUnity(sol::this_state L) ;
}

namespace lua{

	std::string get_full_path( const std::string& name )
	{
		namespace fs = boost::filesystem;
		fs::path path(name);

		fs::path cp =  fs::current_path();
		if( !path.has_root_path() ){
			cp += "/";
			cp += path;
		}else{
			cp = path;
		}

		return cp.generic_string();
	};

	std::string parent_path( const std::string& name )
	{
		namespace fs = boost::filesystem;
		fs::path path(name);

		return path.parent_path().generic_string();
	}

	std::string file_name( const std::string& name )
	{
		namespace fs = boost::filesystem;
		fs::path path(name);

		return path.filename().generic_string();
	}

	void current_path( const std::string& name ){
		namespace fs = boost::filesystem;
		fs::path path(name);
		fs::current_path(path);
	}


	std::string extension( const std::string& name )
	{
		namespace fs = boost::filesystem;
		fs::path path(name);

		return path.extension().string();
	}

	bool remove( const std::string& name )
	{
		namespace fs = boost::filesystem;
		fs::path path(name);

		if (boost::filesystem::exists(path)) {
			boost::system::error_code error_code;
			boost::filesystem::remove_all(path,error_code);
			return true;
		}
		return false;
	}

	bool mkdir( const std::string& name )
	{
		namespace fs = boost::filesystem;
		fs::path path(name);

		if (!boost::filesystem::exists(path)) {
			fs::create_directories(path);
			return true;
		}
		return false;
	}

	bool put_env( const std::string& name,  const std::string& env)
	{
		auto cenv = (name+std::string("=")+env);
		//::putenv((name+std::string("=")+env).c_str());
		//::putenv(cenv.c_str());
		return true;
	}

	bool python( const std::string& name)
	{
		namespace bp = boost::process;
		auto env = boost::this_process::environment();

		std::string path = std::getenv("Gallop_PATH");
		env["Path"] = path+"\\python;" + path+"\\python\\Scripts;" +
				   	  path+"\\python\Lib;" + path+"\\python\\Lib\\site-packages";

		bp::ipstream pipe_stream;
		bp::child c("python " + name, bp::std_out > pipe_stream,env);
		std::string line;
		while (pipe_stream && std::getline(pipe_stream, line) && !line.empty()){
			logs::info_log(boost::format("%1%") % line);
		}

		c.wait();

		return true;
	}

	class str_reader
	{
	public:
		str_reader(const std::string& path, const std::string& delimiter,int prelines, int postlines)
		:m_path(path),
		 m_numPreLines(prelines),
		 m_numPostLines(postlines),
		 m_delimiter(delimiter){};
	protected:
		std::string m_path;
		int m_numPreLines;
		int m_numPostLines;
		std::string m_delimiter;
		std::vector<std::vector<std::string>> m_data;
	public:

		void load(){
			using namespace std;

			int nrow=0;
			int ncol=0;
			std::list< std::vector<std::string> > data;
			std::vector<std::string> labels;


			std::ifstream fin( m_path );
			while( !fin.eof() )
			{
				std::string line;
				std::getline(fin,line);
				vector<string> vStr;
				boost::split( vStr, line, boost::is_any_of( m_delimiter.c_str() ), boost::token_compress_on );
				if( vStr.size() ){
					nrow++;
					data.push_back(vStr);
					ncol = std::max(ncol,(int)vStr.size());
				}
			}

			int nPreLines = m_numPreLines;
			while(data.size() && nPreLines--)
				data.pop_front();
			int nPostLines = m_numPostLines;
			while(data.size() && nPostLines--)
				data.pop_back();
			m_data.clear();
			m_data.insert(m_data.end(), data.begin(),data.end());
		}

		const std::vector<std::vector<std::string>>& data()const{ return m_data; }
	};

	auto get_local_name =[]()
	{
		std::string strCodePage = boost::locale::util::get_system_locale();
		std::locale loc = boost::locale::generator().generate(strCodePage);
		return std::use_facet<boost::locale::info>(loc).encoding();
	};


	sol::table file2strtable( const std::string& pstr, const std::string& dele ,sol::this_state L)
	{
		auto local_cp = get_local_name();

		std::string pathStr = boost::locale::conv::from_utf<char>(pstr, local_cp);

		namespace fs = boost::filesystem;
		fs::path path(pathStr);

		if (!boost::filesystem::exists(path)) {
			throw( "File does not excist: " + pstr );
			logs::error_log(boost::format("File does not excist: %1%") % pstr.c_str());
		}
		str_reader reader(pstr,dele,0,0);
		reader.load();
		auto&& data = reader.data();
		sol::state_view lua(L);
		sol::table res = lua.create_table();
		for(int ii=0; ii < data.size(); ii++){
			res[ii+1] = sol::as_table(data[ii]);
		}
		return res;
	}
	sol::table file2numtable( const std::string& pstr, const std::string& dele , int prel, int postl, sol::this_state L)
	{
		auto local_cp = get_local_name();

		std::string pathStr = boost::locale::conv::from_utf<char>(pstr, local_cp);

		namespace fs = boost::filesystem;
		fs::path path(pathStr);

		if (!boost::filesystem::exists(path)) {
			throw( "File does not excist: " + pstr );
			logs::error_log(boost::format("File does not excist: %1%") % pstr.c_str());
		}
		str_reader reader(path.generic_string(),dele,prel,postl);
		reader.load();
		auto&& data = reader.data();
		sol::state_view lua(L);
		sol::table res = lua.create_table();

		for(int ii=0; ii < data.size(); ii++){
			std::vector<double> nums(data[ii].size());
			for(int jj=0;jj<data[ii].size();jj++){
				try {
					nums[jj]=std::stod(data[ii][jj]);
				}catch(...){
					nums[jj]=std::nan("1");
				}
			}
			res[ii+1] = sol::as_table(nums);
		}
		return res;
	}
	sol::table file2numtable( const std::string& pstr, const std::string& dele ,sol::this_state L)
	{
		return file2numtable( pstr,dele,0,0,L);
	}

	std::string utf8_to_local( const std::string& pstr)
	{
		auto local_cp = get_local_name();
		std::string str = boost::locale::conv::from_utf<char>(pstr, local_cp);
		return str;
	}

	std::string local_to_utf8( const std::string& pstr)
	{
		auto local_cp = get_local_name();
		std::string str = boost::locale::conv::to_utf<char>(pstr, local_cp);
		return str;
	}

}


